package com.ninth_group.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ninth_group.constant.CityQueryConstants;
import com.ninth_group.constant.F7DConstants;
import com.ninth_group.constant.TFDConstants;
import com.ninth_group.po.CityInfo;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Component
public class ReuseCodeService {
    @Resource
    private RedisSerializerUtil redisSerializerUtil;

    /**
     * 获取城市ids
     * @param provinceName 省份名称
     * @param cityName 城市名称
     * @param hiveUtil 工具类
     */
    public List<String> getCityInfoByCid(String provinceName,
                                         String cityName,
                                         HiveUtil hiveUtil)
            throws JsonProcessingException {
        Set<CityInfo> ci = getCitiesInfo(hiveUtil);
        return CityInfoUtil.getCityIds(ci, provinceName, cityName, hiveUtil);
    }

    /**
     * 从redis中获取数据
     * @param cityIds 城市id集合
     * @param type 数据类型
     * @return 返回从查询redis结果
     * @param <T> 泛型类型
     * @throws JsonProcessingException 异常
     */
    public <T> List<T> getDataFromRedis(List<String> cityIds, Class<T> type,
                                        boolean hourOrDay, boolean pOrc)
            throws JsonProcessingException {
        // 预定义返回结果
        List<T> voList = new ArrayList<>();

        // true -> 24小时数据  false -> 7天数据

        // 省份缓存key前缀
        String keyP = hourOrDay ?
                TFDConstants.CITY_WEATHER_24H_P_INFO :
                F7DConstants.CITY_WEATHER_7D_P_INFO;

        // 城市缓存key前缀
        String keyC = hourOrDay ?
                TFDConstants.CITY_WEATHER_24H_C_INFO :
                F7DConstants.CITY_WEATHER_7D_C_INFO;

        // 定义缓存key前缀
        String keyPrefix = pOrc ? keyP : keyC;

        // 先查询redis中的数据
        for (int i = 0; i < (hourOrDay ? 24 : 7); i++) {
            String key = keyPrefix + '_'
                    + cityIds.getFirst() + "_" + i;
            T data = redisSerializerUtil.get(key, type);
            if (data != null) voList.add(data);
        }
        return voList;
    }

    /**
     * 从redis中获取数据
     * @param key 缓存key
     * @param type 数据类型
     * @return 返回从查询redis结果
     * @param <T> 泛型类型
     * @throws JsonProcessingException 异常
     */
    public <T> List<T> getDataFromRedis(String key, Class<T> type)
            throws JsonProcessingException {
        return redisSerializerUtil.getList(key, type);
    }

    /**
     * 添加数据到redis中
     * @param voList 数据
     * @param keyPrefix key前缀
     * @param keyPartResolver 解析key, 获取列表中对象的city_id
     * @param expireTime 过期时间
     * @param timeUnit 时间单位
     * @param <T> 数据类型
     * @throws JsonProcessingException 异常
     */
    public <T> void addToRedis(List<T> voList, String keyPrefix,
                           Function<T, String> keyPartResolver,
                           long expireTime, TimeUnit timeUnit)
            throws JsonProcessingException {
        for (int i = 0; i < voList.size(); i++) {
            T item = voList.get(i);
            String key = keyPrefix + '_' +
                    keyPartResolver.apply(item) + "_" + i; // 缓存key

            redisSerializerUtil.set(key, voList.get(i),
                    expireTime, timeUnit);
        }
    }

    public <T> void addToRedis(List<T> voList, String key, long expireTime, TimeUnit timeUnit)
            throws JsonProcessingException {
        redisSerializerUtil.set(key, voList, expireTime, timeUnit);
    }

    /**
     * 查询所有城市信息
     *
     * @param hiveUtil 工具类
     * @return Set<CityInfo>
     * @throws JsonProcessingException 异常
     */
    private Set<CityInfo> getCitiesInfo(HiveUtil hiveUtil) throws JsonProcessingException {
        // 查询redis中所有城市信息
        Set<CityInfo> cityInfo = redisSerializerUtil.get(
                CityQueryConstants.ALL_CITY_INFO,
                new TypeReference<>() {
                });

        Set<CityInfo> ci;

        // 如果没有, 查询数据库并添加到redis中
        if (cityInfo == null || cityInfo.isEmpty()) {
            ci = CityInfoUtil.getCityInfo(hiveUtil);
            redisSerializerUtil.set(CityQueryConstants.ALL_CITY_INFO, ci,
                    CityQueryConstants.CACHE_TIME, TimeUnit.MINUTES);
        }
        // 如果有, 则使用redis中的数据
        else return cityInfo;
        return ci;
    }
}
